/*
 * Copyright (c) 2001-2003,2016 Mario de Sousa (msousa@fe.up.pt)
 *
 * This file is part of the Modbus library for Beremiz and matiec.
 *
 * This Modbus library is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
 * General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this Modbus library.  If not, see <http://www.gnu.org/licenses/>.
 *
 * This code is made available on the understanding that it will not be
 * used in safety-critical situations without a full and competent review.
 */

/* mb_master.h */

#ifndef MODBUS_MASTER_H
#define MODBUS_MASTER_H
#ifdef ARDUINO

#include <STM32FreeRTOS.h>

#endif
#ifdef windows_x86

#include<pthread.h>

#endif
#ifdef SYLIXOS

#include <pthread.h>

#endif

#include <time.h> /* struct timespec data structure */
#include "plc_modbus.h"

typedef unsigned char u8;
typedef unsigned short u16;

#include "mb_addr.h"  /* get definition of common variable types and error codes */

/***********************************************************************

	 Note: All functions used for sending or receiving data via
	       modbus return these return values.


	Returns:	string_length if OK
			-1 on internal error or port failure
			-2 on timeout
			-3 if a valid yet un-expected frame is received!
			-4 for modbus exception errors
			   (in this case exception code is returned in *error_code)

***********************************************************************/

/* FUNCTION 0x01   - Read Coils
 * Bits are stored on an int array, one bit per int.
 */
int read_output_bits(u8 slave,
                     u16 start_addr,
                     u16 count,
                     u16 *dest,
                     int dest_size,
                     int send_retries,
                     u8 *error_code,
                     uint32_t response_timeout,
                     void *data_access_mutex,
                     u8 crc_reverse, client_node_t *node
);

#define read_coils(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) \
        read_output_bits(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)

/* FUNCTION 0x01   - Read Coils
 * Bits are stored on an uint32_t array, 32 bits per uint32_t.
 * Unused bits in last uint32_t are set to 0.
 */
int read_output_bits_u32(u8 slave,
                         u16 start_addr,
                         u16 count,
                         uint32_t* dest,
                         int send_retries,
                         u8 *error_code,
                         uint32_t response_timeout,
                         u8 crc_reverse, client_node_t *node);

#define read_coils_u32(p1, p2, p3, p4, p5, p6, p7, p8) \
        read_output_bits_u32(p1, p2, p3, p4, p5, p6, p7, p8)

/* FUNCTION 0x02   - Read Discrete Inputs
 * Bits are stored on an int array, one bit per int.
 */
int read_input_bits(u8 slave,
                    u16 start_addr,
                    u16 count,
                    u16 *dest,
                    int dest_size,
                    int send_retries,
                    u8 *error_code,
                    uint32_t response_timeout,
                    void *data_access_mutex,
                    u8 crc_reverse, client_node_t *node
);

#define read_discrete_inputs(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) \
        read_input_bits(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)

/* FUNCTION 0x02   - Read Discrete Inputs
 * Bits are stored on an uint32_t array, 32 bits per uint32_t.
 * Unused bits in last uint32_t are set to 0.
 */
int read_input_bits_u32(u8 slave,
                        u16 start_addr,
                        u16 count,
                        uint32_t* dest,
                        int send_retries,
                        u8 *error_code,
                        uint32_t response_timeout,
                        u8 crc_reverse, client_node_t *node);

#define read_discrete_inputs_u32(p1, p2, p3, p4, p5, p6, p7, p8) \
        read_input_bits_u32(p1, p2, p3, p4, p5, p6, p7, p8)

/* FUNCTION 0x03   - Read Holding Registers */
int read_output_words(u8 slave,
                      u16 start_addr,
                      u16 count,
                      u16 *dest,
                      int dest_size,
                      int send_retries,
                      u8 *error_code,
                      uint32_t response_timeout,
                      void *data_access_mutex,
                      u8 crc_reverse, client_node_t *node
);

#define read_holding_registers(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) \
        read_output_words(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)

/* FUNCTION 0x03   - Read Holding Registers
 * u16 registers are stored in array of uint32_t, two registers per uint32_t.
 * Unused bits of last uint32_t element are set to 0.
 */
int read_output_words_u32(u8 slave,
                          u16 start_addr,
                          u16 count,
                          uint32_t* dest,
                          int send_retries,
                          u8 *error_code,
                          uint32_t response_timeout,
                          u8 crc_reverse, client_node_t *node);

#define read_holding_registers_u32(p1, p2, p3, p4, p5, p6, p7, p8) \
        read_output_words_u32(p1, p2, p3, p4, p5, p6, p7, p8)

/* FUNCTION 0x03   - Read Holding Registers
 * return the array with the data to the calling function
 */
int read_output_words_u16_ref(u8 slave,
                              u16 start_addr,
                              u16 count,
                              u16 **dest,
                              int send_retries,
                              u8 *error_code,
                              uint32_t response_timeout,
                              u8 crc_reverse, client_node_t *node);

#define read_holding_registers_u16_ref(p1, p2, p3, p4, p5, p6, p7, p8) \
        read_output_words_u16_ref(p1, p2, p3, p4, p5, p6, p7, p8)

/* FUNCTION 0x04   - Read Input Registers */
int read_input_words(u8 slave,
                     u16 start_addr,
                     u16 count,
                     u16 *dest,
                     int dest_size,
                     int send_retries,
                     u8 *error_code,
                     uint32_t response_timeout,
                     void *data_access_mutex,
                     u8 crc_reverse, client_node_t *node
);

#define read_input_registers(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) \
        read_input_words(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)

/* FUNCTION 0x04   - Read Input Registers
 * u16 registers are stored in array of uint32_t, two registers per uint32_t.
 * Unused bits of last uint32_t element are set to 0.
 */
int read_input_words_u32(u8 slave,
                         u16 start_addr,
                         u16 count,
                         uint32_t* dest,
                         int send_retries,
                         u8 *error_code,
                         uint32_t response_timeout,
                         u8 crc_reverse, client_node_t *node);

#define read_input_registers_u32(p1, p2, p3, p4, p5, p6, p7, p8) \
        read_input_words_u32(p1, p2, p3, p4, p5, p6, p7, p8)

/* FUNCTION 0x04   - Read Input Registers
 * return the array with the data to the calling function
 */
int read_input_words_u16_ref(u8 slave,
                             u16 start_addr,
                             u16 count,
                             u16 **dest,
                             int send_retries,
                             u8 *error_code,
                             uint32_t response_timeout,
                             u8 crc_reverse, client_node_t *node);

#define read_input_registers_u16_ref(p1, p2, p3, p4, p5, p6, p7, p8) \
        read_input_words_u16_ref(p1, p2, p3, p4, p5, p6, p7, p8)

/* FUNCTION 0x05   - Force Single Coil */
int write_output_bit(u8 slave,
                     u16 coil_addr,
                     u16 state,
                     int send_retries,
                     u8 *error_code,
                     uint32_t response_timeout,
                     void *data_access_mutex,
                     u8 crc_reverse, client_node_t *node
);

#define force_single_coil(p1, p2, p3, p4, p5, p6, p7, p8) \
        write_output_bit(p1, p2, p3, p4, p5, p6, p7, p8)

/* FUNCTION 0x06   - Write Single Register */
int write_output_word(u8 slave,
                      u16 reg_addr,
                      u16 value,
                      int send_retries,
                      u8 *error_code,
                      uint32_t response_timeout,
                      void *data_access_mutex,
                      u8 crc_reverse, client_node_t *node
);

#define write_single_register(p1, p2, p3, p4, p5, p6, p7, p8) \
        write_output_word(p1, p2, p3, p4, p5, p6, p7, p8)

/* FUNCTION 0x0F   - Force Multiple Coils */
int write_output_bits(u8 slave,
                      u16 start_addr,
                      u16 coil_count,
                      u16 *data,
                      int send_retries,
                      u8 *error_code,
                      uint32_t response_timeout,
                      void *data_access_mutex,
                      u8 crc_reverse, client_node_t *node
);

#define force_multiple_coils(p1, p2, p3, p4, p5, p6, p7, p8, p9) \
        write_output_bits(p1, p2, p3, p4, p5, p6, p7, p8, p9)

/* FUNCTION 0x0F   - Force Multiple Coils
 * Bits should be stored on an uint32_t array, 32 bits per uint32_t.
 * Unused bits in last uint32_t should be set to 0.
 */
int write_output_bits_u32(u8 slave,
                          u16 start_addr,
                          u16 coil_count,
                          uint32_t* data,
                          int send_retries,
                          u8 *error_code,
                          uint32_t response_timeout,
                          u8 crc_reverse, client_node_t *node);

#define force_multiple_coils_u32(p1, p2, p3, p4, p5, p6, p7, p8) \
        write_output_bits_u32(p1, p2, p3, p4, p5, p6, p7, p8)

/* FUNCTION 0x10   - Force Multiple Registers */
int write_output_words(u8 slave,
                       u16 start_addr,
                       u16 reg_count,
                       u16 *data,
                       int send_retries,
                       u8 *error_code,
                       uint32_t response_timeout,
                       void *data_access_mutex,
                       u8 crc_reverse, client_node_t *node
);

#define force_multiple_registers(p1, p2, p3, p4, p5, p6, p7, p8, p9) \
        write_output_words(p1, p2, p3, p4, p5, p6, p7, p8, p9)

/* FUNCTION 0x10   - Force Multiple Registers
 * u16 registers are stored in array of uint32_t, two registers per uint32_t.
 * Unused bits of last uint32_t element are set to 0.
 */
int write_output_words_u32(u8 slave,
                           u16 start_addr,
                           u16 reg_count,
                           uint32_t* data,
                           int send_retries,
                           u8 *error_code,
                           uint32_t response_timeout,
                           u8 crc_reverse, client_node_t *node);

#define force_multiple_registers_u32(p1, p2, p3, p4, p5, p6, p7, p8) \
        write_output_words_u32(p1, p2, p3, p4, p5, p6, p7, p8)

/* Initialise the Modbus Library to work as Master only */
int mb_master_init(int nd_count);

/* Shut down the Modbus Library */
int mb_master_done();

/* Establish a connection to a remote server/slave.
 * The address type (naf_tcp, naf_rtu, naf_ascii) specifies the lower
 * layer to use for the newly opened node.
 */
int mb_master_connect(client_node_t *);

/* Shut down a connection to a remote server/slave */
int mb_master_close(client_node_t *);

/* Tell the library that communications will be suspended for some time. */
/* RTU and ASCII versions ignore this function
 * TCP version closes all the open tcp connections (connections are automatically
 *   re-established the next time an IO function to the slave is requested).
 *   To be more precise, the TCP version makes an estimate of how long
 *   the silence will be based on previous invocations to this exact same
 *   function, and will only close the connections if this silence is
 *   expected to be longer than 1 second!
 */
int mb_master_tcp_silence_init();

#endif /* MODBUS_MASTER_H */
